package com.webinsky.web.resource;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ZeroCopyHttpOutputMessage;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.WebSession;
import org.synchronoss.cloud.nio.multipart.util.MimeUtility;

import com.webinsky.article.domain.MisExcelArticle;
import com.webinsky.article.domain.MisExcelArticleBody;
import com.webinsky.article.domain.MisExcelArticleIndex;
import com.webinsky.article.domain.MisExcelArticleVideo;
import com.webinsky.article.service.ArticleManagement;
import com.webinsky.common.proj.Lang;
import com.webinsky.domain.resource.ResOrder;
import com.webinsky.domain.resource.ResOrders;
import com.webinsky.domain.resource.ResType;
import com.webinsky.domain.resource.Resource;
import com.webinsky.domain.resource.Resources;
import com.webinsky.service.resource.ResManagement;
import com.webinsky.web.data.CheckResFilter;
import com.webinsky.web.data.ExportTemplate;
import com.webinsky.web.data.ResForm;
import com.webinsky.web.data.ResNameForm;
import com.webinsky.web.data.Response;
import com.webinsky.web.data.RessForm;
import com.webinsky.web.data.SearchResFilter;
import com.webinsky.web.utils.ExportToExcelUtil;
import com.webinsky.web.utils.FileManager;
import com.webinsky.web.utils.WebSessionUtils;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Controller
public class ResResource {
	
	private static final Logger logger = LoggerFactory.getLogger(ResResource.class);

	@Value("${resource.upload.path}")
	private String basePath;
	
	private FileManager fileManager;
	@Autowired
	private ResManagement resManagement;
	@Autowired
	private ArticleManagement articleManagement;
	
	@PostConstruct
	public void init(){
//		String usrHome = System.getProperty("user.home");
//		basePath = usrHome + "/misumires";
		File baseFile = new File(basePath);
		if (!baseFile.exists()) {
			baseFile.mkdirs();
		}
		fileManager = FileManager.create(basePath);
	}
	
	private ResForm convert(Resource res){
		ResForm resForm = new ResForm();
		resForm.name = res.getName();
		resForm.file = res.getFileName();
		resForm.uid = res.getUid();
		resForm.url = res.getUrl();
		resForm.type = res.getType().getType();
		resForm.lang = res.getLanguage().getLang();
		resForm.siteId = String.valueOf(res.getSiteId());
		resForm.created = res.getCreated();
		return resForm;
	}
	
	@PostMapping(value = "/resource/{siteId}/{lang}/excel/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE})
	public @ResponseBody Mono<Response<String>> uploadArticleExcel(@PathVariable("lang")String lang, 
				@RequestPart("file") FilePart filePart, 
					@PathVariable("siteId")String siteId,
						WebSession session){
		String filename = filePart.filename();
		String splitFileName[] = filename.split("_");
		String strSiteId = splitFileName[0];
		String strLang = splitFileName[1];
		if ( !siteId.equals(strSiteId) || !lang.equals(strLang) ) {
			return Mono.just(Response.create("", 502, "文件名字和请求的BookMode或则lang不同"));
		}
		
		Mono<String> monofilePath = fileManager.saveExcelFile(filePart, siteId, filename, lang);
		if ( monofilePath != null ){
			return monofilePath.flatMap(filePath -> {
				File file = new File(filePath);
				int userId = WebSessionUtils.getAccount(session).getId();
				String userName = WebSessionUtils.getAccount(session).getLoginName();
				try {
					List<ExportTemplate> templates = ExportToExcelUtil.load(file);
					Map<Integer, List<MisExcelArticle>> artiles = new HashMap<>();
					templates.forEach( t -> {
						if ( artiles.get(t.getOperation()) == null ){
							artiles.put(t.getOperation(), new ArrayList<>());
						}
						MisExcelArticle art = new MisExcelArticle();
						art.setArticleAbstract(t.getArticleAbstract());
						art.setArticleNo(t.getArticleNo());
						art.setArticleTitle(t.getArticleTitle());
						int articleIndex = 0;
						for ( int i = 0; i < t.getWorkflow().size(); i ++ ){
							if ( articleIndex == 0 ){
								MisExcelArticleIndex misIndex = new MisExcelArticleIndex();
								misIndex.setIndexName(t.getWorkflow().get(i));
								art.getIndexes().add(misIndex);
								MisExcelArticleBody articleBody = new MisExcelArticleBody();
								if ( i >= t.getOps().size() ){
									articleBody.setOpContent("");
								} else {
									articleBody.setOpContent(t.getOps().get(i));									
								}
								if ( i >= t.getOpsTips().size()){
									articleBody.setOpTips("");
								} else {
									articleBody.setOpTips(t.getOpsTips().get(i));									
								}
								art.getIndexes().get(articleIndex).getArticleBodys().add(articleBody);
								articleIndex ++;
							} else {
								if ( !t.getWorkflow().get(i).equals(art.getIndexes().get(articleIndex - 1).getIndexName()) ){
									MisExcelArticleIndex misIndex = new MisExcelArticleIndex();
									misIndex.setIndexName(t.getWorkflow().get(i));
									art.getIndexes().add(misIndex);
									MisExcelArticleBody articleBody = new MisExcelArticleBody();
									if ( i >= t.getOps().size() ) {
										articleBody.setOpContent("");
									} else {
										articleBody.setOpContent(t.getOps().get(i));
									}
									if ( i >= t.getOpsTips().size() ){
										articleBody.setOpTips("");
									} else {
										articleBody.setOpTips(t.getOpsTips().get(i));
									}
									art.getIndexes().get(articleIndex).getArticleBodys().add(articleBody);
									articleIndex ++;
								} else {
									MisExcelArticleBody articleBody = new MisExcelArticleBody();
									if ( i >= t.getOps().size() ){
										articleBody.setOpContent("");
									} else {
										articleBody.setOpContent(t.getOps().get(i));
									}
									if ( i >= t.getOpsTips().size() ){
										articleBody.setOpTips("");
									} else {
										articleBody.setOpTips(t.getOpsTips().get(i));
									}
									art.getIndexes().get(articleIndex).getArticleBodys().add(articleBody);
								}	
							}
						}
						// 视频转换
						List<String> videoNames = t.getVideoNames();
						if ( !videoNames.isEmpty() ){
							List<Resource> videos = resManagement.getVideoResourceByNames(videoNames, Integer.valueOf(siteId), Lang.parse(lang));
							videos.forEach( e -> {
								MisExcelArticleVideo misVideo = new MisExcelArticleVideo();
								misVideo.setVideoId(Integer.valueOf(e.getUid()));
								art.getVideos().add(misVideo);
							});							
						}
						art.setUserId(userId);
						art.setUserName(userName);
						art.setCreator(userId);
						artiles.get(t.getOperation()).add(art);
					});
					articleManagement.createExcelArticles(artiles, Integer.valueOf(siteId), Lang.parse(lang));
					return Mono.just(Response.create("", 200, ""));
				} catch (Exception e) {
					e.printStackTrace();
					return Mono.just(Response.create("", 501, e.getMessage()));
				}
			});
		}
		return Mono.just(Response.create("", 501, "保存失败"));
	}
	
	@PostMapping(value = "/resource/{siteId}/{lang}/{type}/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE})
	public @ResponseBody Flux<Response<ResForm>> uploadRes(@PathVariable("lang")String lang, @RequestPart("file") FilePart filePart, 
							@RequestPart("name")String name,
							@PathVariable("type")String type,
							@PathVariable("siteId")String siteId){
		logger.info("[uploadRes]");
		ResType resType = ResType.parse(type);
		if ( resType != null ){
			// 保存文件
			String filename = filePart.filename();
			String fName = "";
			String fFileName = String.valueOf(new Date().getTime());
			String filenames[] = filename.split("\\.");
			String extendName = "";
			if ( filenames.length == 2 ) {
				extendName = filenames[1];
			}
			fFileName = fFileName + "." + extendName;
			final String finalFileName = fFileName;
//			try {
//				fName = new String(filename.getBytes("ISO-8859-1"), "UTF-8");;
//				fFileName = URLDecoder.decode(name, "utf-8");
//				logger.info("[uploadRes] name = " + fName);
//				logger.info("[uploadRes] name = " + fFileName);
//			} catch (UnsupportedEncodingException e) {
//				logger.error("[uploadRes] error", e);
//			}
//			final String fN = fName;
//			final String fF = fFileName;
			
//				final String file_name = URLEncoder.encode(filename, "utf-8");
			try {
				logger.info("[uploadRes] orgin filename = " + filename);
				logger.info("[uploadRes] utf8 filename = " + new String(filename.getBytes(), "UTF-8"));
				logger.info("[uploadRes] ISO filename = " + new String(filename.getBytes(), "ISO-8859-1"));
				logger.info("[uploadRes] name = " + URLDecoder.decode(name, "utf-8"));
//				fFileName = String.valueOf(now.getTime());
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Flux<String> filePath = fileManager.saveResFile(filePart.content(), resType, siteId, filename, lang);
			if ( filePath != null ){
				return filePath.flatMap(path -> {
					Resource res = new Resource();
					res.setFileName(filename); // 显示名称
					res.setName(filename); // 文件名称
					res.setType(resType);
					res.setLanguage(Lang.parse(lang));
					res.setSiteId(Integer.valueOf(siteId));
//					res.setUrl("/resource/" + bookmode + "/" + lang + "/" + type + "/" + name);
					res.setUrl("/support/res/" + siteId + "/" + lang + "/material/" + ("image".equals(type) ? "pic" : "mov") + "/" + filename);
					resManagement.createRes(res);
					return Flux.just(Response.create(convert(res), 200, ""));
				});
			}
		}
		return Flux.just(Response.create(null, 501, "文件保存失敗"));
	}
	
	@GetMapping("/resource/{bookmode}/{lang}/{type}/{name}/download")
	public Mono<Void> downloadRes(ServerHttpResponse response, 
				ServerHttpRequest request,
				@PathVariable("bookmode") String bookmode,
				@PathVariable("lang") String lang,
				@PathVariable("type") String type,
				@PathVariable("name") String name){
		
		if ( type != null && name != null && bookmode != null && lang != null){
			ResType resType = ResType.parse(type);
			if ( resType != null ){
				ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
				zeroCopyResponse.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + name);
				File file = fileManager.readResFile(resType, bookmode, name, lang);
				zeroCopyResponse.getHeaders().set(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
				return zeroCopyResponse.writeWith(file, 0, file.length());
			}
		}
		return null;
	}
	
	@PostMapping(value = "/resource/{siteId}/{lang}/{type}", produces = MediaType.APPLICATION_JSON_VALUE)
	public @ResponseBody Mono<Response<RessForm>> getResByPagnation(@RequestBody SearchResFilter filter){
		ResType resType = ResType.parse(filter.type);
		int siteId = Integer.valueOf(filter.siteId);
		Lang lg = Lang.parse(filter.lang);
		ResOrders resOrders = new ResOrders();
		if ( filter.orders != null && filter.orders.orders != null ){
			filter.orders.orders.forEach(o -> {
				ResOrder resOrder = new ResOrder();
				resOrder.setField(o.field);
				resOrder.setAscOrDesc(o.ascOrDes);
				resOrders.getOrders().add(resOrder);
			});
		}
		Resources resources = resManagement.getResourcesByPagnation(resType, siteId, lg, filter.pageStart, filter.pageSize, resOrders);
		RessForm form = new RessForm();
		resources.getResources().forEach(e -> {
			ResForm rf = new ResForm();
			rf.name = e.getName();
			rf.file = e.getFileName();
			rf.type = e.getType().getType();
			rf.uid = e.getUid();
			rf.url = e.getUrl();
			rf.lang = e.getLanguage().getLang();
			rf.siteId = String.valueOf(e.getSiteId());
			rf.created = e.getCreated();
			form.forms.add(rf);
		});
		form.totalCount = resources.getTotalCount();
		return Mono.just(Response.create(form, 200, ""));
		
	}

	@PostMapping(value = "/resource/rename", produces = MediaType.APPLICATION_JSON_VALUE)
	public @ResponseBody Mono<Response<String>> resRename(@RequestBody ResNameForm form){
		// 重新设置资源名称
		ResType type = ResType.parse(form.type);
		if ( type != null ){
			resManagement.resRename(type, Integer.valueOf(form.uid), form.name);			
			return Mono.just(Response.create("", 200, ""));
		}
		return Mono.just(Response.create("", 501, "[]资源类型不对ResTyppe = null"));
	}
	
	@PostMapping(value = "/resource/{bookmode}/{lang}/{type}/search")
	public @ResponseBody Mono<Response<RessForm>> searchImagesByName(@RequestBody SearchResFilter filter){
		Lang lg = Lang.parse(filter.lang);
		int siteId = Integer.valueOf(filter.siteId);
		ResType resType = ResType.parse(filter.type);
		String decodingName = filter.name;
		try {
				decodingName = URLDecoder.decode(filter.name, "utf-8");
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		ResOrders resOrders = new ResOrders();
		if ( filter.orders != null && filter.orders.orders != null ){
			filter.orders.orders.forEach(o -> {
				ResOrder resOrder = new ResOrder();
				resOrder.setField(o.field);
				resOrder.setAscOrDesc(o.ascOrDes);
				resOrders.getOrders().add(resOrder);
			});
		}
		Resources resources = resManagement.getResourcesByName(lg, siteId, decodingName, resType, filter.pageStart, filter.pageSize, resOrders);
		RessForm form = new RessForm();
		resources.getResources().forEach(e -> {
			form.forms.add(convert(e));
		});
		form.totalCount = resources.getTotalCount();
		return Mono.just(Response.create(form, 200, ""));
	}

	@GetMapping(value = "/resource/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
	public @ResponseBody Mono<Response<String>> delRes(@PathVariable("id")String id,@RequestParam("type")int type){
		ResType resType = type == 0 ? ResType.Image : ResType.Video;
		resManagement.delRes(id, resType);
		if ( resType == ResType.Video ){
			articleManagement.deleteRelateVideoByVideIs(Integer.valueOf(id));
		}
		return Mono.just(Response.create("", 200, ""));
	}

	/**
	 * 检查素材名称是否有重复
	 * @param filter
	 * @return
	 */
	@PostMapping(value = "/resource/{bookmode}/{lang}/{type}/check")
	public @ResponseBody Mono<Response<Integer>> checkResByName(@RequestBody CheckResFilter filter){
		int siteId = Integer.valueOf(filter.siteId);
		Lang lg = Lang.parse(filter.lang);
		ResType resType = ResType.parse(filter.type);
		String decodingName = "";
		try {
			decodingName = URLDecoder.decode(filter.name, "utf-8");
		} catch (UnsupportedEncodingException e) {
		}
		boolean isExist = resManagement.checkResourceName(siteId, lg, resType, decodingName);
		int result = isExist ? 1 : 0;
		return Mono.just(Response.create(result, 200, ""));
	}
	
//	public static void main(String args[]) {
//		String str = "QQͼƬ20140702211214.jpg";
//		String str1 = "中文测试";
//		try {
//
//			String s = MimeUtility.decodeText(str1);
//			System.out.println(s);
//		} catch (UnsupportedEncodingException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//	}

}
